package region

import (
	"errors"
	"fmt"
	database "hft/Database"
	"hft/Database/admin"
	"hft/Http/Models/dao"
	"hft/Http/Models/request"
	"hft/Http/Services/base"
	regionres "hft/Http/Services/region/region_res"
	utils "hft/Http/Utils"
	"hft/global"
	"hft/tools"
	"regexp"
	"strconv"
	"strings"

	"gorm.io/gorm"
)

type Region struct{}

func (r *Region) SaveRegion(region *admin.Region) {

	global.OC_DB.Transaction(func(tx *gorm.DB) error {

		region.FirstWord = tools.PinYin(region.Name)

		tx.Omit("id,p_id").Create(&region)

		return nil
	})

}

func BuildTree(nodes []*admin.Region, rootId uint) *admin.Region {
	var root *admin.Region
	for _, node := range nodes {
		if node.ID == rootId {
			root = node
		}
		for _, child := range nodes {
			if child.PID == node.ID {
				node.Districts = append(node.Districts, child)
			}
		}
	}
	return root
}

func (r *Region) GetRegionList() (regions *admin.Region, err error) {

	var regionList []*admin.Region

	var region *admin.Region

	var FlattenRegions []*admin.Region

	global.OC_DB.Find(&regionList)

	region = BuildTree(regionList, 1)

	utils.SetLink(region, region)

	global.OC_DB.Transaction(func(tx *gorm.DB) error {

		// FlattenRegions = append(FlattenRegions, region)

		FlattenRegions = utils.FlattenRegion(region)

		// fmt.Println(tools.JsonParse(FlattenRegions))

		tx.Omit("create_time,deleted_at,p_id").Save(&FlattenRegions)

		return nil
	})

	return region, nil
}

func (*Region) GetRegionByAccount(requestRegion *request.RegionInfoList, claims tools.BaseClaims) (list *utils.Page, err error) {
	account, err := base.FindAccount(claims, global.OC_DB)
	if err != nil {
		return nil, err
	}
	var regions = make([]*regionres.RegionRes, 0)
	global.OC_DB.Model(&admin.Region{}).Scopes(dao.GetRegionDao.GetRegionList(account, requestRegion, global.OC_DB)).Scan(&regions).Limit(-1).Offset(-1).Count(&requestRegion.Total)

	requestRegion.Data = regions

	return &requestRegion.Page, nil

}

// 设置热门城市
func (*Region) SetHot(isHot bool, city int) (err error) {

	var region *admin.Region

	global.OC_DB.First(&region, city)

	if region.Level != "city" {

		return errors.New("该地区不能不为城市，不可设置为热门城市")
	}

	global.OC_DB.Model(&admin.Region{}).Where("id = ?", city).Updates(map[string]interface{}{
		"is_hot": isHot,
	})

	return nil

}

func (*Region) Delete(ids []int, claims tools.BaseClaims) (err error) {

	var account *admin.Account

	err = global.OC_DB.Scopes(dao.ParseAccountDao.Parse(claims, global.OC_DB)).First(&account).Error

	if err != nil {
		return errors.New("未知错误500")
	}

	var regions []*admin.Region

	err = global.OC_DB.Find(&regions, ids).Error

	if err != nil {
		return errors.New("未知错误500")
	}

	if !utils.IsBelongThisRegion(regions, account.RegionLink) {
		return errors.New("你无权先删除该地区")
	}

	err = global.OC_DB.Unscoped().Delete(&regions).Error

	return nil
}

func (*Region) AddRegion(region *admin.Region, claims tools.BaseClaims) (err error) {

	var account *admin.Account
	var parentRegion *admin.Region
	err = global.OC_DB.Scopes(dao.ParseAccountDao.Parse(claims, global.OC_DB)).First(&account).Error
	if err != nil {
		return errors.New("无该账号信息")
	}
	err = global.OC_DB.Where("id = ?", region.PID).First(&parentRegion).Error

	if err != nil {
		return errors.New("无该地区信息")
	}

	if !parentRegion.CanAddChild {
		return errors.New("该地区无法再添加子区域")
	}

	var link = fmt.Sprintf("%v%v,", parentRegion.Link, parentRegion.ID)

	match, err := regexp.MatchString(account.RegionLink, link)

	if err != nil {
		return errors.New("未知错误500")
	}

	if !match {
		return errors.New("你无权在该区域修改或添加信息")
	}

	if region.PreFix != "" {
		res := global.OC_DB.Where("pre_fix = ?", region.PreFix).First(&admin.Region{})

		if res.RowsAffected != 0 {
			return errors.New("该前缀已存在")
		}
	}

	region.Link = link
	if region.Level != "custom" {
		region.CanAddChild = true
	}

	region.FirstWord = tools.PinYin(region.Name)

	var location = strings.Split(region.Center, ",")

	longitude, _ := strconv.ParseFloat(location[0], 64)
	latitude, _ := strconv.ParseFloat(location[1], 64)

	region.Longitude = longitude
	region.Latitude = latitude

	err = global.OC_DB.Model(&admin.Region{}).Omit("manage_id").Create(&region).Error

	if err != nil {
		return errors.New("未知错误500")
	}

	return nil
}

func (*Region) EditRegion(region *admin.Region, claims tools.BaseClaims) (err error) {
	var account *admin.Account
	var parentRegion *admin.Region
	err = global.OC_DB.Scopes(dao.ParseAccountDao.Parse(claims, global.OC_DB)).First(&account).Error
	if err != nil {
		return errors.New("无该账号信息")
	}
	err = global.OC_DB.Where("id = ?", region.PID).First(&parentRegion).Error

	if err != nil {
		return errors.New("无该地区信息")
	}

	var link = fmt.Sprintf("%v%v,", parentRegion.Link, parentRegion.ID)

	match, err := regexp.MatchString(account.RegionLink, link)

	if err != nil {
		return errors.New("未知错误500")
	}

	if !match {
		return errors.New("你无权在该区域修改或添加信息")
	}

	var preRegion *admin.Region

	if region.PreFix != "" {
		global.OC_DB.Where("pre_fix = ?", region.PreFix).First(&preRegion)

		if preRegion.ID != region.ID && preRegion.PreFix == region.PreFix {
			return errors.New("该站点已存在")
		}
	}

	var location = strings.Split(region.Center, ",")

	longitude, _ := strconv.ParseFloat(location[0], 64)
	latitude, _ := strconv.ParseFloat(location[1], 64)

	region.Longitude = longitude
	region.Latitude = latitude

	err = global.OC_DB.Model(&admin.Region{}).Where("id = ?", region.ID).Updates(&admin.Region{
		Name:      region.Name,
		Center:    region.Center,
		FirstWord: tools.PinYin(region.Name),
		Longitude: region.Longitude,
		Latitude:  region.Latitude,
		Base:      database.Base{Sort: region.Sort},
		PreFix:    region.PreFix,
		Alias:     region.Alias,
	}).Error

	if err != nil {
		return errors.New("未知错误500")
	}

	return nil
}

func (*Region) SetDefault(isDefault bool, city int) (err error) {

	var region *admin.Region

	var defaultCity *admin.Region

	global.OC_DB.First(&region, city)

	if region.Level != "city" {

		return errors.New("该地区不能不为城市，不可设置为热门城市")
	}

	err = global.OC_DB.Where("is_default = ?", 1).First(&defaultCity).Error

	if err == nil {
		global.OC_DB.Model(&admin.Region{}).Where("id = ?", defaultCity.ID).Update("is_default", 0)
	}

	global.OC_DB.Model(&admin.Region{}).Where("id = ?", city).Updates(map[string]interface{}{
		"is_default": 1,
	})

	return nil

}

var RegionService = new(Region)
